#include "ostimer.h"

#include "osCpu.h"

#if OS_ENABLE_TIMER == 1 

#if OS_ENABLE_SEMAPHORE == 1
    #include "Semaphore.h"
#else
    #error  "should support semaphore to OS_ENABLE_SEMAPHORE = 1"
#endif


/* 硬定时器列表, 时钟节拍中断中执行*/
static LIST_T       s_TimerHardList;
/* 软定时器列表, 软定时器任务中执行*/
static LIST_T       s_TimerSoftList;

/* 时钟节拍通知软定时器处理 */
static SEMAPHORE_T  s_semSoftTimerTick;
/* 软定时器列表权限获取信号量*/
static SEMAPHORE_T  s_semSoftTimerProtect;

/*****************************************************************************
 * @function        vTimerInit
 * @brief 			初始化一个软件定时器.
 *  
 * @param[in] 		timer 软件定时器.
 * @param[in]       delayTicks 首次运行延时时间.
 * @param[in] 	    periodTicks 周期延时时间.
 * @param[in] 	    timerFunc   定时器回调函数.
 * @param[in] 	    param       定时器回调形参.
 * @param[in] 	    config      软件定时器配置模式.
 * 
 * @return 			None.	
 *
 * ***************************************************************************/
void vTimerInit(TIMER_T *timer, uint32_t delayTicks, uint32_t periodTicks,
        void (*timerFunc)(void *), void *param, uint32_t config)
{
    vNodeInit(&timer->linkNode);
    
    timer->startDelayTicks = delayTicks;
    timer->periodTicks = periodTicks;
    
    timer->timerFunc = timerFunc;
    timer->param = param;
    timer->config = config;
    
    if (delayTicks == 0)
    {
        timer->delayTicks = periodTicks;
    }
    else 
    {
        timer->delayTicks = timer->startDelayTicks;
    }
    
    timer->state = TimerCreated;
}


/*****************************************************************************
 * @function        vTimerStart
 * @brief 			启动定时器.处于创建成功 和停止工作的定时器将运行
 *  
 * @param[in] 		timer 待启动的定时器.
 * 
 * @return 			None.	
 *
 * ***************************************************************************/
void vTimerStart(TIMER_T *timer)
{
    uint32_t primask;
    
    switch (timer->state)
    {
        case TimerCreated:
        case TimerStopped:
            // 初始化启动延时
            timer->delayTicks = timer->startDelayTicks ? timer->startDelayTicks : timer->periodTicks;
            // 更新定时器状态
            timer->state = TimerStarted;
        
            // 添加到对应队列中
            if (timer->config == TIMER_CONFIG_TYPE_HEAD)
            {
                // 硬定时器，在时钟节拍中断中处理， 用临界区保护
                primask = vTaskEnterCritical();
                
                vListAddLast(&s_TimerHardList, &timer->linkNode);
                
                vTaskExitCritical(primask);
            }
            else if (timer->config == TIMER_CONFIG_TYPE_SOFT)
            {
                
                // 获取 软定时器列表访问权限
                vSemaphoreWait(&s_semSoftTimerProtect, 0);
                
                vListAddLast(&s_TimerSoftList, &timer->linkNode);
                
                // 释放 定时器访问权限
                vSemaphoreNotify(&s_semSoftTimerProtect);
            }
        break;
        default:
        break;
    }
}


/*****************************************************************************
 * @function        vTimerStart
 * @brief 			停止定时器.处于已启动 和正在运行的定时器将停止
 *  
 * @param[in] 		timer 待停止的定时器.
 * 
 * @return 			None.	
 *
 * ***************************************************************************/
void vTimerStop(TIMER_T *timer)
{
    uint32_t primask;
    
    switch (timer->state)
    {
        case TimerStarted:
        case TimerRunning:
            // 判断是什么定时器
            if (timer->config == TIMER_CONFIG_TYPE_HEAD)
            {
               // 硬定时器
                primask = vTaskEnterCritical();
                
                vListRemove(&s_TimerHardList, &timer->linkNode);
                
                vTaskExitCritical(primask);
            }
            else if (timer->config == TIMER_CONFIG_TYPE_SOFT)
            {
                // 获取 软定时器列表访问权限
                vSemaphoreWait(&s_semSoftTimerProtect, 0);
                
                vListRemove(&s_TimerSoftList, &timer->linkNode);
                
                // 释放 定时器访问权限
                vSemaphoreNotify(&s_semSoftTimerProtect);
            }

            // 更新定时器状态
            timer->state = TimerStopped;
        break;
        default:
        break;
    }
}


/*****************************************************************************
 * @function        sf_TimerCallFuncList
 * @brief 			定时器列表处理函数.
 *  
 * @param[in] 		list 定时器列表：硬定时器列表 or 软定时器列表.
 * 
 * @return 			None.	
 *
 * ***************************************************************************/
static void sf_TimerCallFuncList(LIST_T *list)
{
    NODE_T *node;
    TIMER_T *timer;
    for (node = list->headNode.nextNode; node != &(list->headNode); node = node->nextNode)
    {
        timer = container_of(node, TIMER_T, linkNode);
        
        /* 延时时间到*/
        if ((timer->delayTicks == 0) | (--timer->delayTicks == 0))
        {
            // 更新定时器状态
            timer->state = TimerRunning;
            
            // 调用定时器处理函数
            timer->timerFunc(timer->param);
            
            // 切换状态
            // 周期性定时器
            if (timer->periodTicks > 0)
            {
                timer->delayTicks = timer->periodTicks;
                timer->state = TimerStarted;
            }
            // 一次性定时器
            else if (timer->periodTicks == 0)
            {
                // 移除定时器列表
                vListRemove(list, node);
                timer->state = TimerStopped;
            }
        }
    }
}

// 软定时器处理线程
static TASK_T       s_taskTimer;
static tTaskStack   s_taskTimerEnv[OS_TIMER_TASK_STACK_SIZE];


/*****************************************************************************
 * @function        f_softTimerEntry
 * @brief 			软定时器线程处理函数. 对软定时器进行tick计数，对于定时完成的进行定时器回调执行
 *  
 * @param[in] 		param 形参.
 * 
 * @return 			None.	
 *
 * ***************************************************************************/
void f_softTimerEntry(void * param)
{
    for (;;)
    {
        // 通知软定时器线程 进行定时器处理
        vSemaphoreWait(&s_semSoftTimerTick, 0);
        
        // 获取 软定时器列表访问权限
        vSemaphoreWait(&s_semSoftTimerProtect, 0);
        
        // 处理软定时器列表
        sf_TimerCallFuncList(&s_TimerSoftList);
        
        // 释放 定时器访问权限
        vSemaphoreNotify(&s_semSoftTimerProtect);
 
    }
}


/*****************************************************************************
 * @function        vTimerModuleInit
 * @brief 			软件定时器模块初始化. 使用软件定时器前，必须进行该初始化
 * 
 * @return 			None.	
 *
 * ***************************************************************************/
void vTimerModuleInit(void)
{
    
    vListInit(&s_TimerHardList);
    vListInit(&s_TimerSoftList);
    vSemaphoreInit(&s_semSoftTimerTick, 0, 0);
    vSemaphoreInit(&s_semSoftTimerProtect, 1, 1);
    
#if OS_TIMER_PRIO >= OS_IDLE_PRIO
    #error "The priority of TimerModule task must be greater than OS_IDLE_PRIO"
#endif
    vTaskCreate(&s_taskTimer, f_softTimerEntry, (void *)0, OS_TIMER_PRIO, s_taskTimerEnv, sizeof(s_taskTimerEnv));

}


/*****************************************************************************
 * @function        vTimerModuleNotify
 * @brief 			通知定时器模块，定时器计时处理.
 * 
 * @return 			None.	
 *
 * ***************************************************************************/
void vTimerModuleNotify(void)
{
        uint32_t primask = vTaskEnterCritical();
    
        // 处理硬定时器列表
        sf_TimerCallFuncList(&s_TimerHardList);
        
        vTaskExitCritical(primask);
        
        // 通知软定时器线程，进行软定时器处理
        vSemaphoreNotify(&s_semSoftTimerTick);
}

/*****************************************************************************
 * @function        vTimerDestroy
 * @brief 			删除定时器.定时器处于已删除状态
 *  
 * @param[in] 		timer 定时器.
 * 
 * @return 			None.	
 *
 * ***************************************************************************/
void vTimerDestroy(TIMER_T *timer)
{
    vTimerStop(timer);
    // 更新定时器状态
    timer->state = TimerDestroyed;
}


/*****************************************************************************
 * @function        vTimerGetInfo
 * @brief 			获取定时器相关参数.
 *  
 * @param[in] 		timer 定时器.
 * @param[out]      info 定时器信息模块.
 * 
 * @return 			None.	
 *
 * ***************************************************************************/
void vTimerGetInfo(TIMER_T *timer, TIMER_INFO_T *info)
{
    uint32_t primask = vTaskEnterCritical();
    
    info->config = timer->config;
    info->param = timer->param;
    info->timerFunc = timer->timerFunc;
    info->periodTicks = timer->periodTicks;
    info->startDelayTicks = timer->startDelayTicks;
    info->state = timer->state;
    
    vTaskExitCritical(primask);

}

#endif // OS_ENABLE_TIMER == 1
